package com.qingfeng.medical.biz.information.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qingfeng.currency.dozer.DozerUtils;
import com.qingfeng.medical.base.domain.entity.BaseEntity;
import com.qingfeng.medical.base.handler.GeneralAuthException;
import com.qingfeng.medical.base.result.ResultCodeEnum;
import com.qingfeng.medical.base.utils.EmailUtils;
import com.qingfeng.medical.biz.information.dao.PatientMapper;
import com.qingfeng.medical.biz.information.domain.dto.PatientSaveDTO;
import com.qingfeng.medical.biz.information.domain.dto.PatientUpdateDTO;
import com.qingfeng.medical.biz.information.domain.entity.Patient;
import com.qingfeng.medical.biz.information.domain.entity.UserInfo;
import com.qingfeng.medical.biz.information.domain.ro.UserInfoRo;
import com.qingfeng.medical.biz.information.domain.vo.UserInfoPageVo;
import com.qingfeng.medical.biz.information.service.PatientService;
import com.qingfeng.medical.biz.information.service.UserInfoService;
import com.qingfeng.medical.biz.message.domain.dto.NewsNotifySaveDTO;
import com.qingfeng.medical.biz.message.domain.enums.IsSeeEnum;
import com.qingfeng.medical.biz.message.domain.enums.UserTypeEnum;
import com.qingfeng.medical.biz.message.service.NewsNotifyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 就诊人表
 *
 * @author 清风学Java
 * @date 2023-04-27 16:26:12
 */
@Service
public class PatientServiceImpl extends ServiceImpl<PatientMapper, Patient> implements PatientService {

    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private EmailUtils emailUtils;
    @Autowired
    private NewsNotifyService newsNotifyService;
    @Autowired
    private DozerUtils dozerUtils;

    /**
     * 分页查询用户就诊人信息
     *
     * @param userInfoPage
     * @param certificatesType
     * @param authStatus
     * @param patientStatus
     * @return
     */
    @Override
    public UserInfoPageVo patientList(Page<UserInfo> userInfoPage,
                                      String certificatesType,
                                      Integer authStatus,
                                      Integer patientStatus) {
        // 先查询用户信息
        Page<UserInfo> infoPage = userInfoService.userInfoPage(userInfoPage, certificatesType, authStatus);

        if (infoPage.getTotal() == 0) {
            return UserInfoPageVo.builder()
                    .total(infoPage.getTotal())
                    .pageSize(infoPage.getPages())
                    .limit(infoPage.getSize())
                    .userInfoRoList(Collections.emptyList())
                    .build();
        }

        // 封用户信息
        List<Long> userInfoId = infoPage.getRecords()
                .stream()
                .map(BaseEntity::getId)
                .collect(Collectors.toList());

        // 根据用户Id批量查询就诊人信息
        LambdaQueryWrapper<Patient> queryWrapper = new LambdaQueryWrapper<Patient>()
                .in(Patient::getUserId, userInfoId)
                .orderByAsc(Patient::getStatus);
        if(ObjectUtil.isNotNull(patientStatus)) {
            queryWrapper.eq(Patient::getStatus, patientStatus);
        }
        Map<Long, List<Patient>> patientMap = baseMapper.selectList(
                        queryWrapper
                )
                .stream()
                .collect(Collectors.groupingBy(Patient::getUserId));

        // 封装数据
        List<UserInfoRo> userInfoRos = infoPage.getRecords()
                .stream()
                .map(r -> {
                    UserInfoRo userInfoRo = dozerUtils.map2(r, UserInfoRo.class);
                    userInfoRo.setPatientList(patientMap.getOrDefault(r.getId(), null));
                    return userInfoRo;
                })
                .collect(Collectors.toList());

        return UserInfoPageVo.builder()
                .total(infoPage.getTotal())
                .pageSize(infoPage.getPages())
                .limit(infoPage.getSize())
                .userInfoRoList(userInfoRos)
                .build();
    }

    /**
     * 保存就诊人信息
     *
     * @param patientSaveDTO
     */
    @Override
    public void savePatient(PatientSaveDTO patientSaveDTO) {
        // 先判断 用户是否重复，直接判断证件号
        List<Patient> patientList = baseMapper.selectList(
                new LambdaQueryWrapper<Patient>()
                        .eq(Patient::getCertificatesNo, patientSaveDTO.getCertificatesNo())
        );

        if (CollUtil.isNotEmpty(patientList)) {
            // 就诊人信息重复
            throw new GeneralAuthException(ResultCodeEnum.FAIL.getCode(), "就诊人信息重复！！！");
        }

        baseMapper.insert(dozerUtils.map2(patientSaveDTO, Patient.class));
    }

    /**
     * 根据Id修改就诊人信息
     *
     * @param patientUpdateDTO
     */
    @Override
    public void updatePatientById(PatientUpdateDTO patientUpdateDTO) {
        // 先判断 用户是否重复，直接判断证件号
        List<Patient> patientList = baseMapper.selectList(
                new LambdaQueryWrapper<Patient>()
                        .eq(Patient::getCertificatesNo, patientUpdateDTO.getCertificatesNo())
                        .ne(Patient::getId, patientUpdateDTO.getId())
        );

        if (CollUtil.isNotEmpty(patientList)) {
            // 就诊人信息重复
            throw new GeneralAuthException(ResultCodeEnum.FAIL.getCode(), "就诊人信息重复！！！");
        }

        baseMapper.updateById(dozerUtils.map2(patientUpdateDTO, Patient.class));
    }

    /**
     * 就诊人认证
     * @param patient
     */
    @Override
    public void authPatient(Patient patient) {
        // 根据Id修改就诊人认证信息
        baseMapper.updateById(patient);

        // 用户认证之后进行消息通知
        String title = "就诊人认证审核"
                + (patient.getStatus() == 1 ? "通过" : "不通过")
                + "通知";
        String content = "尊敬的用户，您在塔城地区医院预约挂号系统的就诊人："
                +patient.getName()
                +"认证信息已于"
                + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd mm:hh:ss"))
                + "审核"
                + (patient.getStatus() == 1 ? "通过" : "不通过。请前往系统检查信息并重新提交！如有问题联系医院管理员。");

        UserInfo userInfo = userInfoService.getById(patient.getUserId());

        // 判断账号是邮箱还是手机号
        if (userInfo.getAccount().contains("@")) {
            // 邮箱
            emailUtils.sendEmail(userInfo.getAccount(), title, content);
        } else {
            // TODO 手机号，发送短信
        }


        // 先将消息写入数据库
        newsNotifyService.saveNewsNotify(
                NewsNotifySaveDTO.builder()
                        .userId(patient.getUserId())
                        .newsTitle(title)
                        .userType(UserTypeEnum.FRONT)
                        .newsContent(content)
                        .isSee(IsSeeEnum.IS_NOT_VIEWED)
                        .build()
        );
    }
}